#!/usr/bin/env python3

__author__ = 'z.Wick.Tone.Burst'
__doc__ = """ Perceptron Learning Algorithm of ML,
    using numpy package."""


import numpy as np
import zt.ML.regression as mlreg
import zt.ML.utils as mltls

# from zt.ML.utils import *
# from zt.ML.regression import LinearRegression



class PLA:
    """The Perceptron Learning Algorithm."""
    def __init__(self, w, y0, datafile, eta=0.1126):
        self.D = mltls.LinearDataSet(datafile, True)
        self.W = np.append(np.array(w), LinearRegression(D))
        self.y0 = y0
        self.eta = eta


    def copy(self):
        # cp = PLA(self.w[0], self.y0, self.)
        pass


    def sign(self, x):
        y = self.W.dot(x)
        if y > 0:
            return 1
        elif y < 0:
            return -1
        else:
            return self.y0


    def update(self, x, y):
        if self.sign(x) == y:
            return 0
        self.W += self.eta * y * np.array([1, ]+ x)
        return 1


    def train(self, D=None):
        pass


    def mistakes(self, tdset=None):
        pass




class Pocket:
    def __init__(self, pla):
        self.pla = pla
        self.best = pla.copy()


    def update(self, D):
        x, y = D.choice(random.choice(self.pla.eset))
        if self.pla.update(x, y) == 0:
            return 0
        if self.pla.mistakes(D) < self.best.mistakes(D):
            self.best = self.pla.copy()
            return 1
        return 0


    def train(self, D, updates, rounds):
        ups = 0
        self.pla.mistakes(D)
        for i in range(rounds):
            ups += self.update(D)
            if ups >= updates:
                break
        return self.best





def test_PLA():
    D = LinearDataSet('./data/pla_train.txt', x0=True)
    # pla = PLA(0, -1, eta=0.5)
    # data = load_data('./data/pla_train.txt')
    return pla.train(randomize(data))[1]
    # return pla.train(data)[1]


def test_pocket():
    # pla = PLA(0, -1, eta=0.5)
    # data = load_data('./data/pocket_train.txt')
    D = LinearDataSet('./data/pocket_train.txt', x0=True)
    pla = PLA(0, -1, D)
    pocket = Pocket(pla)
    pocket.train(D, 50, 2000)
    td = LinearDataSet('./data/pocket_test.txt', x0=True)
    print(pocket.best.W)
    return pocket.best.mistakes(td) / len(td)




if __name__ == '__main__':

    def run():
        # return test_PLA()
        return test_pocket()

    c = 0
    rounds = 1
    import time
    st = time.time()
    for i in range(rounds):

        c += run()

    print('Average Error Rate:', c / rounds)
    et = time.time()
    print('Time Spent:', et - st)